#!/usr/bin/perl

######################################################################
package Swignition::uF::hAudio;
######################################################################

use CGI::Util;
use Swignition::GenericParser::Utils;
use Swignition::MagicString;
use Swignition::uF;
use XML::LibXML qw(:all);
use strict;


sub consume
{
	my $page        = shift;

	unless ( $page->{Profiles}->{'http://purl.org/uF/hAudio/0.9/'}
	||       $page->{Profiles}->{'http://purl.org/NET/haudio'}
	||      !$page->{options}->{uf_strict_profiles})
	{
		return;
	}

	$page->{uF}->{hAudio} = [ parse_all($page) ];
	
	foreach my $a (@{ $page->{uF}->{hAudio} })
	{
		$a->rdf_subject_merge($page);
	}
	
	if (defined $page->{uF}->{hAudio}->[0])
	{
		$page->mergeNS($page->{uF}->{hAudio}->[0]);
	}
}


sub parse_all
{
	my $page   = shift;
	my $within = shift || $page->{DOM};
	my @rv;
	
	my @nodes = searchClass('haudio', $within);
	foreach my $a (@nodes)
	{
		my $A = parse($page, $a);
		push @rv, $A;
	}
	
	return @rv;
} #/sub parse_all


sub uri
{
	my $this = shift;
	my $all  = shift;
	my @rv;

	if (length $this->{_id})
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri.'#'.$this->{_id});
	}
	if (lc($this->{_dom}->tagName) eq 'body')
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri);
	}
	push @rv, Swignition::GenericParser::Utils::BNodeURI($this->{_dom}, 'AudioDescription')
		unless (@rv);
	
	return $rv[0] unless (defined $all);
	while ($all) { shift @rv; $all--; }
	return @rv;
} #/sub uri


sub rdf_subject_merge
{
	my $this    = shift;
	my $page    = shift;
	my $val;
	
	my $subject = Swignition::RDFModel::Subject->new($this->uri);
	$subject->addObject($this);
	$subject->setDom($this->{_dom});
	
	if ($this->{haudio_type} eq 'album')
	{
		$val = Swignition::RDFModel::Value->new('http://purl.org/media/audio#Album', 1);
		$subject->addVal("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", $val);
		
		$val = Swignition::RDFModel::Value->new($this->{album});
		$subject->addVal("http://purl.org/dc/terms/title", $val);
	}
	else
	{
		$val = Swignition::RDFModel::Value->new('http://purl.org/media/audio#Recording', 1);
		$subject->addVal("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", $val);
		
		$val = Swignition::RDFModel::Value->new($this->{title});
		$subject->addVal("http://purl.org/dc/terms/title", $val);
		
		if (length $this->{album} && ! $this->{parent})
		{
			$val = Swignition::RDFModel::Value->new($this->{album});
			$subject->addVal("http://purl.org/dc/terms/isPartOf", $val);
		}
	}
	
	foreach my $x (@{ $this->{contributor} })
	{
		if (UNIVERSAL::can($x, 'uri'))
			{ $val = Swignition::RDFModel::Value->new($x->uri, 1); }
		else
			{ $val = Swignition::RDFModel::Value->new($x); }
		$subject->addVal("http://purl.org/dc/terms/contributor", $val);
	}

	foreach my $x (@{ $this->{publisher} })
	{
		if (UNIVERSAL::can($x, 'uri'))
			{ $val = Swignition::RDFModel::Value->new($x->uri, 1); }
		else
			{ $val = Swignition::RDFModel::Value->new($x); }
		$subject->addVal("http://purl.org/dc/terms/publisher", $val);
	}

	foreach my $x (@{ $this->{published} })
	{
		$val = Swignition::RDFModel::Value->new($x);
		$subject->addVal("http://purl.org/dc/terms/issued", $val);
	}

	if (length $this->{duration})
	{
		$val = Swignition::RDFModel::Value->new($this->{duration});
		$subject->addVal("http://purl.org/media#duration", $val);
	}

	foreach my $x (@{ $this->{category} })
	{
		$val = Swignition::RDFModel::Value->new($x);
		$subject->addVal("http://purl.org/dc/terms/type", $val);
	}

	foreach my $x (@{ $this->{photo} })
	{
		$val = Swignition::RDFModel::Value->new($x, 1);
		$subject->addVal("http://purl.org/media#depiction", $val);
	}

	if (length $this->{description})
	{
		$val = Swignition::RDFModel::Value->new($this->{description});
		$subject->addVal("http://purl.org/dc/terms/description", $val);
	}

	foreach my $x (@{ $this->{sample} })
	{
		$val = Swignition::RDFModel::Value->new($x, 1);
		$subject->addVal("http://purl.org/media#sample", $val);
	}

	foreach my $x (@{ $this->{enclosure} })
	{
		$val = Swignition::RDFModel::Value->new($x, 1);
		$subject->addVal("http://purl.org/media#download", $val);
	}

	foreach my $x (@{ $this->{payment} })
	{
		$val = Swignition::RDFModel::Value->new($x, 1);
		$subject->addVal("http://purl.org/commerce#payment", $val);
	}

	foreach my $x (@{ $this->{url} })
	{
		$val = Swignition::RDFModel::Value->new($x, 1);
		$subject->addVal("http://xmlns.com/foaf/0.1/page", $val);
	}

	if ($this->{price})
	{
		if (UNIVERSAL::can($this->{price}, 'uri'))
		{
			$subject->addVal(
				'http://purl.org/commerce#costs', 
				Swignition::RDFModel::Value->new($this->{price}->qv_uri, 1));
			$subject->addVal(
				'http://buzzword.org.uk/rdf/measure-aux#hasMeasurement', 
				Swignition::RDFModel::Value->new($this->{price}->uri, 1));
		}
		else
		{
			$subject->addVal(
				"http://purl.org/commerce#costs", 
				Swignition::RDFModel::Value->new($this->{price}));
		}
	}
	
	foreach my $x (@{ $this->{items} })
	{
		$val = Swignition::RDFModel::Value->new($x->uri, 1);
		$subject->addVal("http://purl.org/media#contains", $val);
		$subject->addVal("http://purl.org/dc/terms/hasPart", $val);
	}
	
	if ($this->{parent})
	{
		$val = Swignition::RDFModel::Value->new($this->{parent}->uri, 1);
		$subject->addVal("http://purl.org/dc/terms/isPartOf", $val);
	}
	
	$page->mergeSubject($subject);
	
	foreach my $x (@{ $this->{items} })
	{
		$x->rdf_subject_merge($page);
	}
	
} #/sub rdf_subject


sub metadata_ns
{
	my $this = shift;
	return {
		'media' => {
				nsurl=>'http://purl.org/media#',
				title=>'RDF Media Vocab'
			},
		'audio' => {
				nsurl=>'http://purl.org/media/audio#',
				title=>'RDF Media (Audio) Vocab'
			},
		'video' => {
				nsurl=>'http://purl.org/media/video#',
				title=>'RDF Media (Video) Vocab'
			},
		'commerce' => {
				nsurl=>'http://purl.org/commerce#',
				title=>'RDF Commerce Vocab'
			}
		};
} #/sub metadata_ns


sub parse
{
	my $page  = shift;
	my $rv    = { '_dom'=>shift };
	my $pkg = __PACKAGE__;
	if (defined $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') })
		{ return $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') }; }
	else
		{ $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') } = $rv; }
	
	my $root  = $rv->{'_dom'}->cloneNode(1);
	
	my $id = $root->getAttribute('id');
	$rv->{_id} = $id if (length $id);
	$rv->{_page} = $page;
		
	data_patterns($page, $root, 2);

	# Items - too tricky for simple_parse() to handle!
	my ($this_item, $last_item);
	my @items = searchClass('item', $root);
	foreach my $i (@items)
	{
		# Deal with ".haudio .item .item", etc! This shuld work...
		if (length $last_item)
		{
			$this_item = $i->getAttribute('_xpath');
			next if (substr($this_item, 0, length $last_item) eq $last_item);
		}
		$last_item = $i->getAttribute('_xpath');
		
		my $I = parse($page, $i);
		$I->{title} = STRINGIFY($i, 'value') unless (length $I->{title} || length $I->{album});
		$I->{parent} = $rv;
		push @{ $rv->{items} }, $I;
		destroy_element($i);
	}
	
	simple_parse(
		$rv,
		$root,
		[
			['album',       '?'],
			['contributor', 'M*', {embedded=>'hCard'}],
			['category',    '*'],
			['description', '&'],
			['duration',    'D?'],
			['enclosure',   'ru*'],
			['fn',          '?', {'use-key'=>'title'}],
			['payment',     'ru*'],
			['position',    'n?'],
			['photo',       'u*'],
			['price',       'M?', {embedded=>'hMeasure'}],
			['published',   'd*'],
			['publisher',   'M*', {embedded=>'hCard'}], # extension
			['sample',      'ru*'],
			['title',       '?'], # note 'fn' used in preference.
			['url',         'u*']
		]
	);
	
	# Does this represent an album or a track?
	# http://microformats.org/wiki/haudio#More_Semantic_Equivalents
	if (length $rv->{title} && length $rv->{album})
		{ $rv->{haudio_type} = 'track'; }
	elsif (length $rv->{album})
		{ $rv->{haudio_type} = 'album'; }
	elsif (length $rv->{title})
		{ $rv->{haudio_type} = 'track'; }
	else
	{
		$rv->{haudio_type} = 'track';
		
		my $EARL = 'http://www.w3.org/WAI/ER/EARL/nmg-strawman#';
		my $XE   = 'http://buzzword.org.uk/rdf/xearl#';
		my $DC   = 'http://purl.org/dc/terms/';
	
		my $p = Swignition::RDFModel::Subject->new(
			Swignition::GenericParser::Utils::BNodeURI(undef, 'MicroformatErrorReport'));		
		$p->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
			Swignition::RDFModel::Value->new($EARL.'Assertion', 1));
		$p->addVal($EARL.'assertedBy',
			Swignition::RDFModel::Value->new('http://buzzword.org.uk/swignition/#swignition', 1));
		$p->addVal($EARL.'mode',
			Swignition::RDFModel::Value->new($EARL.'automatic', 1));
		$p->addVal($EARL.'result',
			Swignition::RDFModel::Value->new($XE.'error', 1));
		$p->addVal($DC.'abstract',
			Swignition::RDFModel::Value->new(strlang("hAudio requires that one or both of the 'fn' or 'album' properties to be set.", 'en')));
			
		push @{$rv->{ERRORS}}, $p;
	}
	
	bless $rv;

	$rv->do_inheritance;

	Swignition::uF::error_list_process($rv, $page, 'http://microformats.org/wiki/haudio');
	foreach my $item (@{ $rv->{items} })
	{
		Swignition::uF::error_list_process($item, $page, 'http://microformats.org/wiki/haudio');
	}

	return $rv;
	
} #/sub parse


# Inherit certain properties from parent to child
# http://microformats.org/wiki/haudio#Parser_Processing_Notes
sub do_inheritance
{
	my $this = shift;
	
	ITEM: foreach my $item (@{ $this->{items} })
	{
		PROPERTY: foreach my $property (qw(album contributor category published photo))
		{
			next PROPERTY if defined ($item->{$property});
			$item->{$property} = $this->{$property};
		}
		# Recursion.
		$item->do_inheritance;
	}
}

1; #/package Swignition::uF::hAudio

